﻿// Copyright (c) Microsoft Corporation.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Metadata.Edm;
using System.Diagnostics;

namespace EdmMetadataHelpers
{
    /// <summary>
    /// A simple class that shreds a CSDL meta-data into a flatter catalog designed
    /// to make querying easier.
    /// </summary>
    public class EdmCsdlCatalog
    {
        #region Member Variables
        List<AssociationType> _associations = new List<AssociationType>();
        List<EdmProperty> _properties = new List<EdmProperty>();
        List<NavigationProperty> _navigationProperties = new List<NavigationProperty>();
        List<PrimitiveType> _primitives = new List<PrimitiveType>();
        List<EntityType> _entities = new List<EntityType>();
        List<EdmFunction> _functions = new List<EdmFunction>();
        List<EntityContainer> _containers = new List<EntityContainer>();
        List<EntitySetBase> _sets = new List<EntitySetBase>();
        #endregion

        #region Constructors
        /// <summary>
        /// Construct a Catalog from a preloaded EdmItemCollection
        /// </summary>
        /// <param name="items">a preloaded EdmItemCollection</param>
        public EdmCsdlCatalog(EdmItemCollection items)
        {
            Register(items);
        }
        /// <summary>
        /// Construct a Catalog from the path to a csdl file
        /// </summary>
        /// <param name="filepath">The path to the CSDL file</param>
        public EdmCsdlCatalog(string csdlFilepath) : this(new EdmItemCollection(csdlFilepath)) { }
        #endregion

        #region Registration Methods
        public void Register(EdmItemCollection items)
        {
            foreach (GlobalItem item in items)
                Register(item);
        }
        private void Register(GlobalItem item)
        {
            switch (item.BuiltInTypeKind)
            {
                case BuiltInTypeKind.PrimitiveType:
                    Register(item as PrimitiveType);
                    break;
                case BuiltInTypeKind.EntityType:
                    Register(item as EntityType);
                    break;
                case BuiltInTypeKind.AssociationType:
                    _associations.Add(item as AssociationType);
                    break;
                case BuiltInTypeKind.EdmFunction:
                    _functions.Add(item as EdmFunction);
                    break;
                case BuiltInTypeKind.EntityContainer:
                    Register(item as EntityContainer);
                    break;
                default:
                    throw new Exception("Couldn't register {0}".Merge(item.BuiltInTypeKind.ToString()));
            }
        }
        private void Register(EntityType type)
        {
            foreach (EdmMember member in type.Members)
            {
                Register(member);
            }
            _entities.Add(type);
        }
        private void Register(PrimitiveType type)
        {
            _primitives.Add(type);
        }
        private void Register(EdmMember member)
        {
            switch (member.BuiltInTypeKind)
            { 
                case BuiltInTypeKind.EdmProperty:
                    EdmProperty property = member as EdmProperty;
                    _properties.Add(property);
                    break;
                case BuiltInTypeKind.NavigationProperty:
                    NavigationProperty navigationProperty = member as NavigationProperty;
                    _navigationProperties.Add(navigationProperty);
                    break;
                default:
                    System.Diagnostics.Debugger.Break();
                    break;
            }
        }
        /// <summary>
        /// Registers and Schreds an EntityContainer with the Catalog
        /// </summary>
        /// <param name="container"></param>
        private void Register(EntityContainer container)
        {
            foreach (EntitySetBase set in container.BaseEntitySets)
                _sets.Add(set);
            _containers.Add(container);
        }
        #endregion

        #region Properties
        public IEnumerable<EntityType> Entities
        {
            get { return _entities; }
        }
        public IEnumerable<AssociationType> Associations
        {
            get { return _associations; }
        }
        public IEnumerable<EntitySetBase> Sets
        {
            get { return _sets; }
        }
        public IEnumerable<PrimitiveType> Primitives
        {
            get {
                return _primitives;
            }
        }
        public IEnumerable<EdmProperty> Properties
        {
            get { 
                return _properties; 
            }
        }
        public IEnumerable<NavigationProperty> NavigationProperties
        {
            get {
                return _navigationProperties;
            }
        }
        public IEnumerable<EntitySet> EntitySets
        {
            get
            {
                return Sets.OfType<EntitySet>();
            }
        }
        public IEnumerable<RelationshipSet> RelationshipsSets
        {
            get
            {
                return Sets.OfType<RelationshipSet>();
            }
        }
        public IEnumerable<AssociationSet> AssociationSets
        {
            get
            {
                return Sets.OfType<AssociationSet>();
            }
        }
        public IEnumerable<EntityContainer> Containers
        {
            get { return _containers; }
        }
        public IEnumerable<EdmFunction> Functions
        {
            get { return _functions; }
        }
        #endregion
    }
}
